//
//  CSMACAVCSListener.cpp
//  WiFiMACSim
//
//  Created by Christopher Kemsley on 4/1/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "CSMACAVCSListener.hpp"
#include "Settings.hpp"

using namespace Sim ;



CSMACAVCSListener :: CSMACAVCSListener ( ID const & name )
:	TransitionalStateMachineNode<CSMACAVCSListener> ( name )
,	timer()
	{
	registerStateCallback ( kStateIdle , &CSMACAVCSListener::update_idle , "Idle. Waiting for RTS" ) ;
	
	// Transaction control
	registerStateCallback ( kStateWaitForData , &CSMACAVCSListener::update_dataWait , "Waiting for data" ) ;
	
	registerStateCallback ( kStateSendingCTS , &CSMACAVCSListener::update_xmitCTS , "Sending CTS" ) ;
	registerStateCallback ( kStateSendingAck , &CSMACAVCSListener::update_xmitAck , "Sending ACK" ) ;
	
	// VCS States
	registerStateCallback ( kStateVCSSawCTS , &CSMACAVCSListener::update_vcs_saw , "Saw CTS. Waiting for NAV" ) ;
	registerStateCallback ( kStateVCSSawRTS , &CSMACAVCSListener::update_vcs_saw , "Saw RTS. Waiting for NAV" ) ;
	}







void	CSMACAVCSListener :: update_vcs_saw	( Message * incoming , bool completed , bool isBusy )
	{
	if ( timer.isTime() )
		setState ( kStateIdle ) ;
	}







void	CSMACAVCSListener :: update_idle		( Message * incoming , bool completed , bool isBusy )
	{
	if ( incoming != 0 )
		{
		// <cts> + <sifs> + <data> + <sifs> + <ack> + <diffs>
		UInteger	sifs			=	Settings::shared().SIFSDuration ;
		UInteger	difs			=	Settings::shared().DIFSDuration ;
		UInteger	data			=	Settings::shared().dataPacketDuration ;
		UInteger	control			=	Settings::shared().controlPacketDuration ;
		UInteger	waitDuration	=	control*2 + data + sifs*2 + difs ;
		
		
		if ( incoming->target == identity )
			incoming->status = Message::kStatusSuccessful ;
		
		if ( !completed ) return ; // wait for it to complete
		
		switch ( incoming->type )
			{
				case Message::kTypeCTS : {
					if ( incoming->target == identity )
						{
						ThrowException ( "CSMACAVCSListener" , "Should not be receiving CTS in idle state" , __FILE__,__LINE__ ) ;
						}
					else
						{
						timer . skipNext ( waitDuration ) ;
						setState ( kStateVCSSawCTS ) ;
						//std::cout << NodeStamp << "Saw CTS. Ignoring for "<<waitDuration<<". Return date: "<<(System::shared().currentSlot()+waitDuration) << "\n" ;
						}
				} break ;
				
				case Message::kTypeRTS : {
					if ( incoming->target == identity )
						{
						sender = incoming->sender ;
						
						setState(kStateSendingCTS) ;
						message = new Message ( identity , sender , Message::kTypeCTS , Settings::shared().controlPacketDuration ) ;
						Medium::shared().registerMessage(message) ;
						}
					else
						{
						// <rts> + <sifs>
						waitDuration += sifs + control ;
						timer . skipNext ( waitDuration ) ;
						setState ( kStateVCSSawRTS ) ;
						//std::cout << NodeStamp << "Saw RTS. Ignoring for "<<waitDuration<<". Return date: "<<(System::shared().currentSlot()+waitDuration) << "\n" ;
						}
				} break ;
				
				case Message::kTypeACK : {
					//ThrowException ( "CSMACAVCSListener" , "Should not be receiving any ACK in idle state" , __FILE__,__LINE__ ) ;
				} break ;
				
				case Message::kTypeData : {
					//ThrowException ( "CSMACAVCSListener" , "Should not be receiving any data in idle state" , __FILE__,__LINE__ ) ;
				} break ;
			}
		}
	}




void	CSMACAVCSListener :: update_xmitCTS( Message * incoming , bool completed , bool isBusy )
	{
	if ( completed )
		{
		/* Statistics */
		if ( message -> status != Message::kStatusSuccessful )
			{
			//std::cout << NodeStamp << "CTS Message was never received/handled\n" ;
			}
		/* Statistics */
		
		message -> release() ;
		message = 0 ;
		
		timer . skipNext ( Settings::shared().DIFSDuration ) ;
		setState ( kStateWaitForData ) ;
		}
	}
void	CSMACAVCSListener :: update_dataWait	( Message * incoming , bool completed , bool isBusy )
	{
	if ( incoming != 0 )
		{
		if ( incoming->target == identity )
			{
			incoming->status = Message::kStatusSuccessful ;
			
			if ( completed )
				{
				setState(kStateSendingAck) ;
				message = new Message ( identity , sender , Message::kTypeACK , Settings::shared().controlPacketDuration ) ;
				Medium::shared().registerMessage(message) ;
				}
			}
		}
	else if ( timer.isTime() )
		{
		setState ( kStateIdle ) ;
		}
	}
void	CSMACAVCSListener :: update_xmitAck( Message * incoming , bool completed , bool isBusy )
	{
	if ( ! message->isInFlight )
		{
		/* Statistics */
		if ( message -> status != Message::kStatusSuccessful )
			{
			//std::cout << NodeStamp << "ACK Message was never received/handled\n" ;
			}
		/* Statistics */
		
		message -> release() ;
		message = 0 ;
		
		timer . skipNext ( Settings::shared().DIFSDuration ) ;
		setState ( kStateIdle ) ;
		}
	}

